﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ActualSong.cs" company="Jens Horstmann">
//   Copyright (c) Jens Horstmann. All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace MiniMusicPlayer.Classes
{
    using System;
    using System.Collections.Specialized;

    /// <summary>
    /// The actual song.
    /// </summary>
    public class ActualSong
    {
        /// <summary>
        /// The _actual pointer.
        /// </summary>
        private int? _actualPointer;

        /// <summary>
        /// The current.
        /// </summary>
        private Song current;

        /// <summary>
        /// Initializes a new instance of the <see cref="ActualSong"/> class.
        /// </summary>
        /// <param name="playlist">
        /// The playlist.
        /// </param>
        public ActualSong(Playlist playlist)
        {
            this.actualPointer = null;
            this.Playlist = playlist;
            this.Playlist.ShuffledSongs.CollectionChanged += this.SongCollectionChanged;
        }

        /// <summary>
        /// Gets the playlist.
        /// </summary>
        public Playlist Playlist { get; private set; }

        /// <summary>
        /// Gets or sets the actual pointer.
        /// </summary>
        private int? actualPointer
        {
            get
            {
                return this._actualPointer;
            }

            set
            {
                this._actualPointer = value;
                this.GetActualSong();
            }
        }

        /// <summary>
        /// Gets the current.
        /// </summary>
        public Song Current
        {
            get
            {
                return this.current;
            }

            private set
            {
                this.current = value;
                this.RaiseActualSongChangedEvent();
            }
        }

        /// <summary>
        /// The song collection changed.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void SongCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (this.actualPointer != null && (int)this.actualPointer < this.Playlist.ShuffledSongs.Count)
            {
                // Search for old song
                if (this.Playlist.ShuffledSongs[(int)this.actualPointer] != this.Current)
                {
                    if (this.Playlist.ShuffledSongs.Contains(this.Current))
                    {
                        this.actualPointer = this.Playlist.ShuffledSongs.IndexOf(this.Current);
                    }
                }
            }
            else if(this.Playlist.ShuffledSongs.Count > 0)
            {
                this.actualPointer = 0;
            }
            else
            {
                this.actualPointer = null;
            }
        }

        /// <summary>
        /// The has next.
        /// </summary>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool HasNext()
        {
            if (!this.Playlist.ShuffledSongs.Contains(this.Current))
            {
                return false;
            }

            return this.actualPointer + 1 < this.Playlist.ShuffledSongs.Count;
        }

        /// <summary>
        /// The has previous.
        /// </summary>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        private bool HasPrevious()
        {
            return this.actualPointer - 1 > 0;
        }

        /// <summary>
        /// The get actual song.
        /// </summary>
        /// <returns>
        /// The <see cref="Song"/>.
        /// </returns>
        private Song GetActualSong()
        {
            // C#6 FTW?
            if (this.Playlist != null && this.Playlist.ShuffledSongs != null && this.Playlist.ShuffledSongs.Count > 0)
            {
                return this.Current = this.Playlist.ShuffledSongs[(int)this.actualPointer];
            }

            return null;
        }

        /// <summary>
        /// The next song.
        /// </summary>
        /// <returns>
        /// The <see cref="Song"/>.
        /// </returns>
        public Song NextSong()
        {
            if (this.actualPointer == null)
            {
                this.actualPointer = 0;
                return this.GetActualSong();
            }

            // No more elements; decide what to do
            if (!this.HasNext())
            {
                // Random
                if (this.Playlist.PlaylistMode == PlaylistMode.Random)
                {
                    this.Playlist.ShuffledSongs.Shuffle();
                }

                this.actualPointer = 0;
            }
            else
            {
                this.actualPointer++;
            }

            return this.GetActualSong();
        }

        /// <summary>
        /// The previous song.
        /// </summary>
        /// <returns>
        /// The <see cref="Song"/>.
        /// </returns>
        public Song PreviousSong()
        {
            if (this.actualPointer != null && this.actualPointer > 0)
            {
                this.actualPointer--;
                return this.Current;
            }

            // Let the Song begin again
            return this.Current;
        }

        /// <summary>
        /// The actual song changed.
        /// </summary>
        public event Action<Song> ActualSongChanged;

        /// <summary>
        /// The raise actual song changed event.
        /// </summary>
        public void RaiseActualSongChangedEvent()
        {
            if (this.ActualSongChanged != null)
            {
                this.ActualSongChanged(this.Current);
            }
        }

        /// <summary>
        /// The stop.
        /// </summary>
        public void Stop()
        {
            this.actualPointer = null;
            this.Current = null;
        }

        /// <summary>
        /// The song changed.
        /// </summary>
        /// <param name="song">
        /// The song.
        /// </param>
        internal void SongChanged(Song song)
        {
            this.actualPointer = this.Playlist.ShuffledSongs.IndexOf(song);
            this.GetActualSong();
        }
    }
}